package pe.mutacion;

import java.util.ArrayList;

import pe.algenetico.MiRandom;
import pe.cromosoma.Cromosoma;
import pe.cromosoma.FactoriaCromosoma;

public class Heuristica extends MutacionPadre{
	private ArrayList<int[]> perIndices;
	
	public Cromosoma mutar(Cromosoma individuo, MiRandom ran, int param){
		//param es el numero de puntos a seleccionar	
		//Hallamos los puntos de permuta
		int[] puntos=new int[param];
		perIndices = new ArrayList<int[]>();
		
		for(int i = 0;i<param;i++){
			puntos[i] = ran.r.nextInt(individuo.getLong_cromo());
			for(int j=0; j<=i;j++){
				if (i!=j && puntos[i]==puntos[j]) i--;
			}
		}
		
		
		
		Cromosoma[] permutaciones = damePermutaciones(param, puntos, individuo);
		for (int j =0; j<factorial(param); j++){
			if(individuo.getAptitud()>permutaciones[j].getAptitud()) individuo=permutaciones[j];
		}
		
		return individuo;
	}
	
	private Cromosoma[] damePermutaciones(int param, int[] puntos, Cromosoma individuo){
		Cromosoma[] permuta = new Cromosoma[factorial(param)];
		//Evaluamos todos los cromosomas
		int[] valorPuntos = new int[param];
		
		for(int i=0; i<param; i++){
			valorPuntos[i] = individuo.getIndices()[puntos[i]];
		}
		
		permute(valorPuntos ,0,param);
		
		for(int i= 0; i < permuta.length; i++){
			Cromosoma indAux = FactoriaCromosoma.getCromosoma(0, individuo);
			
			//Sustituimos los valores de la permutacion
			for(int j = 0; j < param; j++){
				int index = puntos[j];
				indAux.getIndices()[index]=perIndices.get(i)[j]; 
			}
			indAux.setAptitud(indAux.evalua());
			permuta[i] = indAux;
		}
		
		return permuta;
	}
	
	private int factorial(int n){
		int factorial=1;
		while ( n!=0) {
			  factorial=factorial*n;
			  n--;
			}
		return factorial;
	}
	
	/*
	 * Devuelve todas las permutaciones posibles sobre el array de entrada ps.  
	 */
	public void permute(int[] ps, int start, int n) {
	    int tmp = 0;
	    int[] pAux = new int[ps.length];
	    for(int k=0; k <ps.length;k++) pAux[k] = ps[k];
	    perIndices.add(pAux);
	    
	    
	    if (start < n) {
	      for (int i = n - 2; i >= start; i--) {
	        for (int j = i + 1; j < n; j++) {
	          //intercambiamos el elemento i por el j
	          tmp = ps[i];
	          ps[i] = ps[j];
	          ps[j] = tmp;

	          permute(ps, i + 1, n);
	        }

	        tmp = ps[i];
	        for (int k = i; k < n - 1;)
	          ps[k] = ps[++k];
	        ps[n - 1] = tmp;
	      }
	    }
	    
	  }
	
}
